#pragma once
#include <map>
#include <vector>
#include <cmath>


double Rand(double f,double t);

//hidden nodes
class BPNode
{
public:
	BPNode(){ thres = Rand(-1,1); outputval=0; delta=0; }
	double thres;

	void input(double dval)
	{
		double dX = dval - thres;
		outputval = 1.0/(1.0+exp(-dX));
	}	
	double outputval;
	double delta; //use for training
};

class BPEdge
{
public:
	BPEdge(){ weight = Rand(-1,1); dLastChange = 0; }
	double weight;

	double dLastChange;
};

typedef std::vector<double> DoubleArray;

class BPNetwork
{
public:	
	typedef std::pair<int,int> NodeID;   //level , index
	typedef std::pair<NodeID,NodeID> EdgeID;   //from node to node

	void Init(int nHiddenLevels, int NodeCount);

	void Teach(double dIn, double dOut);
	void Out(double dIn,double& dOut);
	//teach the net work
	void Teach(const DoubleArray& inputData, const DoubleArray& teachData);
	//get data out,resize the output data first
	void Out(const DoubleArray& inputData, DoubleArray& outputData);


protected:
	BPNode& Node(int nLevel,int nIdx){ return m_nodes[NodeID(nLevel,nIdx)];}
	BPEdge& Edge(const NodeID& f, const NodeID& t){ return m_edges[EdgeID(f,t)]; }



	

protected:
	typedef std::map<NodeID, BPNode> NodeMap;
	NodeMap m_nodes;
	typedef std::map<EdgeID,BPEdge> EdgeMap;
	EdgeMap m_edges;

	std::vector<int> mLevelNodesCount; //node count of each level

	double _calNodeInput(int nLevel, int nIdx);
	void _autoResize(int nInput, int nOutput);
};
